/*
 * saveconfig.c
 *
 *  Created on: 2021年10月9日
 *      Author: soliber
 */
#include "saveconfig.h"
#include "string.h"

const config_t const *pconfig= (config_t*)CFG_ADDR;

bool valid_checked = false;
bool valid = false;

/**
 * @brief 判断配置数据是否有效，对FLASH中保存的参数进行CRC
 *
 * @return 数据是否有效
 */
bool config_is_valid(void)
{
	if(valid_checked == false)
	{
		//CRC校验
		uint32_t crc = HAL_CRC_Calculate(&hcrc, (uint32_t*)pconfig, (sizeof(config_t)-sizeof(uint32_t))/sizeof(uint32_t));
		if(pconfig->crc == crc)
		{
			valid = true;
		}
		else
		{
			valid = false;
		}
		valid_checked = true;
	}
	return valid;
}

/**
 * @brief 设置校准参数并写到FLASH
 *
 * @param cali 校准参数结构体指针
 *
 * @return 状态
 * @retval 0 成功
 * @retval -1 CRC校验不通过，可能是写入过程出错导致
 * @retval -2 FLASH擦除失败
 * @retval -3 FLASH编程失败
 */
int8_t config_cali(cali_t *cali)
{
	config_t cfg;
	memcpy(&cfg,pconfig,sizeof(config_t));
	memcpy(&(cfg.cali),cali,sizeof(cali_t));

	//计算CRC
	cfg.crc = HAL_CRC_Calculate(&hcrc, (uint32_t*)&cfg, (sizeof(config_t)-sizeof(uint32_t))/sizeof(uint32_t));

	//FLASH解锁
	HAL_FLASH_Unlock();

	//擦除最后一页
	FLASH_EraseInitTypeDef EraseInit;
	uint32_t PageError;
	EraseInit.Banks = FLASH_BANK_1;
	EraseInit.NbPages = 1;
	EraseInit.PageAddress = CFG_ADDR;
	EraseInit.TypeErase = FLASH_TYPEERASE_PAGES;
	if(HAL_FLASHEx_Erase(&EraseInit, &PageError)!=HAL_OK)
	{
		HAL_FLASH_Lock();
		return -2;
	}

	//编程
	uint64_t dest = CFG_ADDR,*src = (uint64_t*)&cfg;
	int cnt = (sizeof(config_t)/sizeof(uint64_t)) + ((sizeof(config_t)%sizeof(uint64_t))?1:0);
	while(cnt--)
	{
		if(HAL_OK!=HAL_FLASH_Program(FLASH_TYPEPROGRAM_DOUBLEWORD, dest, *src))
		{
			HAL_FLASH_Lock();
			return -3;
		}
		dest += 8;
		src ++;
	}

	//FLASH上锁
	HAL_FLASH_Lock();

	//校验参数
	valid_checked = false;
	if(config_is_valid() == false)
	{
		return -1;
	}

	return 0;
}

/**
 * @brief 出厂设置设备ID和类型，以及校准参数
 *
 * @param cfg 配置参数结构体指针，其中crc部分可以为任意值，由本函数进行计算
 *
 * @return 状态
 * @retval 0 成功
 * @retval -1 CRC校验不通过，可能是写入过程出错导致
 * @retval -2 FLASH擦除失败
 * @retval -3 FLASH编程失败
 */
int8_t config_device(config_t *cfg)
{
	//计算CRC
	cfg->crc = HAL_CRC_Calculate(&hcrc, (uint32_t*)cfg, (sizeof(config_t)-sizeof(uint32_t))/sizeof(uint32_t));

	//FLASH解锁
	HAL_FLASH_Unlock();

	//擦除最后一页
	FLASH_EraseInitTypeDef EraseInit;
	uint32_t PageError;
	EraseInit.Banks = FLASH_BANK_1;
	EraseInit.NbPages = 1;
	EraseInit.PageAddress = CFG_ADDR;
	EraseInit.TypeErase = FLASH_TYPEERASE_PAGES;
	if(HAL_FLASHEx_Erase(&EraseInit, &PageError)!=HAL_OK)
	{
		HAL_FLASH_Lock();
		return -2;
	}

	//编程
	uint64_t dest = CFG_ADDR,*src = (uint64_t*)cfg;
	int cnt = (sizeof(config_t)/sizeof(uint64_t)) + ((sizeof(config_t)%sizeof(uint64_t))?1:0);
	while(cnt--)
	{
		if(HAL_OK!=HAL_FLASH_Program(FLASH_TYPEPROGRAM_DOUBLEWORD, dest, *src))
		{
			HAL_FLASH_Lock();
			return -3;
		}
		dest += 8;
		src ++;
	}

	//FLASH上锁
	HAL_FLASH_Lock();

	//校验参数
	valid_checked = false;
	if(config_is_valid() == false)
	{
		return -1;
	}

	return 0;
}
